function Promise(excutor) {
    const self = this;

    self.status = pending;
    self.data = undefined;
    self.callbacks = [];

    try {
        excutor(resolve, reject);
    } catch (error) {
        reject(error);
    }

    function resolve(value) {
        if (self.status !== pending) {
            return
        }

        self.status = resolved;
        self.data = value;
        if (self.callbacks.length > 0) {
            setTimeout(() => {
                self.callbacks.forEach(callbacksObj => {
                    callbacksObj.onResolved(value)
                });
            })
        }
    }

    function reject(reason) {
        if (self.status !== pending) {
            return
        }

        self.status = rejected;
        self.data = reason;
        if (self.callbacks.length > 0) {
            setTimeout(() => {
                self.callbacks.forEach(callbacksObj => {
                    callbacksObj.onRejected(value)
                });
            })
        }
    }
}
Promise.prototype.then = function(onResolved, onRejected) {
    const self = this;

    onResolved = typeof onResolved === 'function' ? onResolved : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };

    return new Promise((resolve, reject) => {
        function handle(callback) {
            try {
                const result = callback(self.data)
                if (result instanceof Promise) {
                    result.then(resolve, reject)
                } else {
                    resolve(result)
                }
            } catch (error) {
                reject(error)
            }
        }

        if (self.status === pending) {
            self.callbacks.push({
                onResolved(value) {
                    handle(onResolved)
                },
                onRejected(reason) {
                    handle(onRejected)
                }
            })
        } else if (self.status === resolved) {
            setTimeout(() => {
                handle(onResolved);
            })
        } else {
            setTimeout(() => {
                handle(onRejected);
            })
        }
    })
}

Promise.prototype.catch = function(onRejected) {
    return this.then(undefined, onRejected)
}

Promise.resolved = function(value) {
    return new Promise((resolve, reject) => {
        if (value instanceof Promise) {
            value.then(resolve, reject)
        } else {
            resolve(value)
        }
    })
}

Promise.rejected = function(value) {
    return new promised((resolve, reject) => {
        reject(reason)
    })
}

Promise.all = function(promises) {
    const values = new Array(promises.length)
    let resolveCount = 0
    return new Promise((resolve, reject) => {
        promises.forEach((p, index) => {
            Promise.resolve(p).then(
                value => {
                    resolveCount++;
                    values[index] = value
                    if (resolveCount === promises.length) {
                        resolve(values)
                    }
                },
                reson => {
                    reject(reason)
                }
            )
        })
    })

}

Promise.race = function(promises) {
    return new Promise((resolve, reject) => {
        promises.forEach((p, index) => {
            Promise.resolve(p).then(
                value => {
                    resolve(value)
                },
                reason => {
                    reject(reason)
                }
            )
        })
    })
}
